package cn.jilian.meta.handler.generators;

import java.lang.reflect.Array;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.jilian.common.util.MapUtil;
import cn.jilian.data.util.DataConverter;
import cn.jilian.entity.MField;
import cn.jilian.entity.Meta;
import cn.jilian.meta.handler.CompGenerator;
import cn.jilian.meta.handler.GeneratorManager;
import cn.jilian.meta.handler.constants.HandlerConstants;
import cn.jilian.meta.handler.domain.FormatRegex;
import cn.jilian.meta.handler.domain.Function;
import cn.jilian.meta.handler.domain.Model;
import cn.jilian.meta.handler.domain.XField;

public class SimpleModelGenerator implements CompGenerator<Model>{

	private GeneratorManager manager;
	
	public SimpleModelGenerator(GeneratorManager manager) {
		this.manager=manager;
	}
	
	public static final Map<Integer,String> typeMap=HandlerConstants.typeMap;
	
	@Override
	public Model convert(Meta meta,Map<String,Object> extConfig) {
		String name=meta.getCode();
		List<MField> fs=meta.getFields();
		Model model=new Model();
		List<Object> fields=new ArrayList<>(fs.size());
		Map<String,Object> validators=new HashMap<>();
		for(MField f:fs) {
			XField field=new XField();
			field.setName(f.getName());
			field.setType(typeMap.get(f.getType()));
			fields.add(field);
			if(f.getAttr(MField.FORMULA)!=null) {
				String formula=(String) f.getAttr(MField.FORMULA);
				field.setCalculate(new Function(formula));
				if(f.getAttr(MField.STORECOLUMN)==null) {
					field.setPersist(Boolean.FALSE);
				}
			}
			if(f.getAttr(MField.DEFAULT_VALUE)!=null) {
				Object value=f.getAttr(MField.DEFAULT_VALUE);
				field.setDefaultValue(value);
			}
			if(f.getAttr(MField.REQUIRED)!=null) {
				validators.put(f.getName(), "presence");
			}
			if(f.getAttr(MField.INCLUSION)!=null) {
				Map<String,Object> config=new HashMap<>();
				Object list=f.getAttr(MField.INCLUSION);
				config.put("type", XField.VALIDATE_INCLUSION);
				convert(config,list,f);
				MapUtil.putMultiValue(validators, f.getName(), config);
			}
			if(f.containsAttr(MField.EXCLUSION)) {
				Map<String,Object> config=new HashMap<>(4);
				Object list=f.getAttr(MField.EXCLUSION);
				config.put("type", XField.VALIDATE_EXCLUSION);
				convert(config,list,f);
				MapUtil.putMultiValue(validators, f.getName(), config);
			}
			if(f.containsAttr(MField.MAXLENGTH)||f.containsAttr(MField.MAXLENGTH)) {
				Map<String,Object> config=new HashMap<>(4);
				config.put("type", "length");
				if(f.containsAttr(MField.MAXLENGTH)) {
					config.put("max", f.getAttr(MField.MAXLENGTH));
				}
				if(f.containsAttr(MField.MINLENGTH)) {
					config.put("min",f.getAttr(MField.MINLENGTH));
				}
				MapUtil.putMultiValue(validators, f.getName(), config);
			}
			if(f.containsAttr(MField.DATAFORMAT)) {
				Map<String,Object> config=new HashMap<>(2);
				config.put("type", "format");
				if(f.getType().equals(Types.CHAR)) {
					config.put("matcher", new FormatRegex((String)f.getAttr(MField.DATAFORMAT)));
				}
				MapUtil.putMultiValue(validators, f.getName(), config);
			}
			
		}
		model.setName(name);
		model.setValidators(validators);
		model.setExtend("Ext.data.Model");
		model.setFields(fields);
		return model;
		
	}
	
	
	private void convert(Map<String,Object> config,Object value,MField f) {
		
		Integer type=((Number)f.getAttr(MField.ELEMENTTYPE, Types.CHAR)).intValue();
		if(type.equals(Types.CHAR)) {
			config.put("list", value);
		}else {
			if(Array.class.isAssignableFrom(value.getClass())) {
				Object[] options=(Object[])value;
				Collection<Object> ops=new ArrayList<>(options.length);
				for(Object option:options) {
					ops.add(DataConverter.convert(option, type));
				}
				config.put("list", ops);
			}
			
			
		}
	}

}
